home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / doom / quake2.zip / TF1_2SRC.ZIP / QUAKE / FORTRESS / SOURCE / TFORT.QC < prev    next >
Text File  |  1996-09-10  |  65KB  |  2,365 lines

  1. /*
  2.     TeamFortress 1.2    -    7/9/96
  3.  
  4.     Robin Walker, John Cook, Ian Caughley.
  5.  
  6.     Functions specific to the TeamFortress QuakeC patch.
  7. */
  8.  
  9. // Function Prototypes
  10. void() GrenadeExplode;
  11. void() spike_touch;
  12. void() bound_other_ammo;
  13.  
  14. // Help Functions
  15. void() TeamFortress_MOTD;
  16. void() TeamFortress_HelpIndex;
  17. void() TeamFortress_HelpWeapon;
  18. void() TeamFortress_HelpClass;
  19. void() TeamFortress_HelpItem;
  20. void() TeamFortress_HelpGeneral;
  21. void() TeamFortress_HelpPreImp;
  22. void() TeamFortress_HelpShowPreImp;
  23.  
  24. // Multiskin Functions
  25. void(float skinno) Multiskin_SetSkin;
  26.  
  27. // Team Functions
  28. float(float tno) TeamFortress_TeamGetColor;
  29. void(float tno) TeamFortress_TeamSetColor;
  30. float() TeamFortress_TeamPutPlayerInTeam;
  31.  
  32. // Impulse Functions
  33. void() TeamFortress_ChangeClass;
  34. void() TeamFortress_Inventory;
  35. void() TeamFortress_ShowTF;
  36. void() TeamFortress_PrimeGrenade;
  37. void() TeamFortress_ThrowGrenade;
  38. void() TeamFortress_DetonatePipebombs;
  39. // Pre-Impulse Functions
  40. void(float tflag) TeamFortress_Toggle;
  41. void(float scanrange) TeamFortress_Scan;
  42. void(float timer) TeamFortress_SetDetpack;
  43. void(float skinno) TeamFortress_Multiskin;
  44.  
  45. // Player Class Handling Functions
  46. void() TeamFortress_SetHealth;
  47. void() TeamFortress_SetEquipment;
  48. void() TeamFortress_SetSpeed;
  49. void() TeamFortress_SetSkin;
  50. void() TeamFortress_PrintClassName;
  51. void() TeamFortress_RemoveTimers;
  52. void() TeamFortress_CheckClassStats;
  53. float(entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo;
  54. float(entity Retriever, float WeaponType) TeamFortress_CanGetWeapon;
  55. float(entity Retriever, entity Armor) TeamFortress_CanGetArmor;
  56. float(entity Retriever, entity Items) TeamFortress_AddBackpackItems;
  57.  
  58. // Weapon Handling Functions
  59. void() TeamFortress_SniperWeapon;
  60. void() TeamFortress_ExplodePerson;
  61. void() NormalGrenadeTouch;
  62. void() NormalGrenadeExplode;
  63. void() ConcussionGrenadeTouch;
  64. void() ConcussionGrenadeExplode;
  65. void() ConcussionGrenadeTimer;
  66. void() NailGrenadeTouch;
  67. void() NailGrenadeExplode;
  68. void() NailGrenadeNailEm;
  69. void() NailGrenadeLaunchNail;
  70. void() MirvGrenadeTouch;
  71. void() MirvGrenadeExplode;
  72. void(vector org, entity shooter) MirvGrenadeLaunch;
  73. void() PipebombTouch;
  74.  
  75. // Item Handling Functions
  76. void() TeamFortress_DetpackSet;
  77. void() TeamFortress_DetpackExplode;
  78. void() TeamFortress_DetpackTouch;
  79. void() TeamFortress_DetpackCountDown;
  80.  
  81. // Utility Functions
  82. void(entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce;
  83. entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan;
  84. void(string halias, float himpulse1, float himpulse2) TeamFortress_Alias;
  85.  
  86. // Cyclic Event Functions
  87. void() TeamFortress_Regenerate;
  88. void() TeamFortress_CheckforCheats;
  89.  
  90. void(entity Item, entity AP, float method) tfgoalitem_RemoveFromAP;
  91. //=========================================================================
  92. // IMPULSE FUNCTIONS
  93. //=========================================================================
  94. //=========================================================================
  95. // Impulse function which Toggles Game Settings
  96. void(float tflag) TeamFortress_Toggle =
  97. {
  98.     local entity e,bak;
  99.     local string db;
  100.  
  101.     // prevent pre-impulse from triggering anything else
  102.     self.impulse = 0;
  103.     self.last_impulse = 0;
  104.  
  105.     // Classkin/Multiskin
  106.     if (tflag == TF_TOGGLE_SKIN)
  107.     {
  108.         if (toggleflags & TFLAG_SKIN)
  109.         {
  110.             bprint("Classkin On.\n");
  111.             toggleflags = toggleflags - (toggleflags & TFLAG_SKIN);
  112.  
  113.             bak = self;
  114.             // Change everyone's skins to their class
  115.             e = find(world, classname, "player");
  116.             while (e)
  117.             {
  118.                 self = e;
  119.                 TeamFortress_SetSkin();
  120.                 
  121.                 e = find(e, classname, "player");
  122.             }
  123.             self = bak;
  124.         }
  125.         else
  126.         {
  127.             bprint("Multiskin On.\n");
  128.             toggleflags = (toggleflags | TFLAG_SKIN);
  129.         }
  130.  
  131.         return;
  132.     }
  133.  
  134.     // Class Persistence between lvls On/Off
  135.     if (tflag == TF_TOGGLE_CLASS_PERSIST)
  136.     {
  137.         if (toggleflags & TFLAG_CLASS_PERSIST)
  138.         {
  139.             bprint("Class Persistence Off.\n");
  140.             toggleflags = toggleflags - (toggleflags & TFLAG_CLASS_PERSIST);
  141.         }
  142.         else
  143.         {
  144.             bprint("Class Persistence On.\n");
  145.             toggleflags = (toggleflags | TFLAG_CLASS_PERSIST);
  146.         }
  147.  
  148.         return;
  149.     }
  150.  
  151.     // turn auto placement of players in team on/off
  152.     if (tflag == TF_TOGGLE_AUTOTEAM)
  153.     {
  154.         if (toggleflags & TFLAG_AUTOTEAM)
  155.         {
  156.             bprint("Auto team placement Off.\n");
  157.             toggleflags = toggleflags - (toggleflags & TFLAG_AUTOTEAM);
  158.         }
  159.         else
  160.         {
  161.             bprint("Auto team placement On.\n");
  162.             toggleflags = toggleflags | TFLAG_AUTOTEAM;
  163.         }
  164.     }
  165.  
  166.     // Respawn delays Cycle
  167.     if (tflag == TF_TOGGLE_RESPAWNDELAY)
  168.     {
  169.         if ((toggleflags & TFLAG_RESPAWNDELAY) && (toggleflags & TFLAG_RESPAWNDELAY2))
  170.         {
  171.             // turn all off
  172.             bprint("Respawn Delay Off.\n");
  173.             toggleflags = toggleflags - (toggleflags & TFLAG_RESPAWNDELAY);
  174.             toggleflags = toggleflags - (toggleflags & TFLAG_RESPAWNDELAY2);
  175.         }
  176.         else if (toggleflags & TFLAG_RESPAWNDELAY)
  177.         {
  178.             // level one on, move to level two (off, on)
  179.             bprint("Respawn Delay On, ");
  180.             db = ftos(TF_RESPAWNDELAY2);
  181.             bprint(db);
  182.             bprint(" seconds.\n");
  183.  
  184.             toggleflags = toggleflags | TFLAG_RESPAWNDELAY2;
  185.             toggleflags = toggleflags - TFLAG_RESPAWNDELAY;
  186.         }
  187.         else if (toggleflags & TFLAG_RESPAWNDELAY2)
  188.         {
  189.             // level two on, move to level three (both flags set)
  190.             bprint("Respawn Delay On, ");
  191.             db = ftos(TF_RESPAWNDELAY3);
  192.             bprint(db);
  193.             bprint(" seconds.\n");
  194.  
  195.             toggleflags = toggleflags | TFLAG_RESPAWNDELAY | TFLAG_RESPAWNDELAY2;
  196.         }
  197.         else
  198.         {
  199.             // set to level one
  200.             bprint("Respawn Delay On, ");
  201.             db = ftos(TF_RESPAWNDELAY1);
  202.             bprint(db);
  203.             bprint(" seconds.\n");
  204.  
  205.             toggleflags = toggleflags | TFLAG_RESPAWNDELAY;
  206.             toggleflags = toggleflags - (toggleflags & TFLAG_RESPAWNDELAY2);
  207.         }
  208.     }
  209.  
  210.     // Cheat Checking On/Off
  211.     if (tflag == TF_TOGGLE_CHEATCHECK)
  212.     {
  213.         if (toggleflags & TFLAG_CHEATCHECK)
  214.         {
  215.             bprint("Cheat Checking Off.\n");
  216.             toggleflags = toggleflags - (toggleflags & TFLAG_CHEATCHECK);
  217.  
  218.             // Remove everyone's cheattimers
  219.             e = find(world, classname, "timer");
  220.             while (e)
  221.             {
  222.                 if (e.think == TeamFortress_CheckforCheats)
  223.                 {
  224.                     bprint("Removed cheattimer.\n");
  225.                     remove(e);
  226.                     e = find(world, classname, "timer");
  227.                 }
  228.                 else
  229.                     e = find(e, classname, "timer");
  230.             }
  231.         }
  232.         else
  233.         {
  234.             bprint("Cheat Checking On.\n");
  235.             toggleflags = (toggleflags | TFLAG_CHEATCHECK);
  236.             // Create everyone's cheattimers
  237.             e = find(world, classname, "player");
  238.             while (e)
  239.             {
  240.                 bak = spawn();
  241.                 bak.nextthink = time + 20;
  242.                 bak.think = TeamFortress_CheckforCheats;
  243.                 bak.classname = "timer";
  244.                 bak.owner = e;
  245.                 
  246.                 e = find(e, classname, "player");
  247.             }
  248.         }
  249.  
  250.         return;
  251.     }
  252.  
  253.     // FortressMap details On/Off    (see readme.txt for more info)
  254.     if (tflag == TF_TOGGLE_FORTRESSMAP)
  255.     {
  256.         if (toggleflags & TFLAG_FORTRESSMAP)
  257.         {
  258.             bprint("FortressMap Off.\n");
  259.             toggleflags = toggleflags - (toggleflags & TFLAG_FORTRESSMAP);
  260.         }
  261.         else
  262.         {
  263.             bprint("FortressMap On.\n");
  264.             toggleflags = (toggleflags | TFLAG_FORTRESSMAP);
  265.         }
  266.  
  267.         return;
  268.     }
  269.  
  270. };
  271.  
  272. //=========================================================================
  273. // Handles the Multiskin Pre-Impulse to Set Skin
  274. void(float skinno) TeamFortress_Multiskin =
  275. {
  276.     // prevent help pre-impulse from triggering anything else
  277.     self.impulse = 0;
  278.     self.last_impulse = 0;
  279.  
  280.     Multiskin_SetSkin(skinno);
  281. };
  282.  
  283. //=========================================================================
  284. // Player change class function
  285. void() TeamFortress_ChangeClass =
  286. {
  287.     local entity spot;
  288.  
  289.     cvar_set("sv_maxspeed", "600");
  290.     // Only change playerclass once - remove this if you want to change on the fly
  291.     if ( self.playerclass != PC_UNDEFINED )
  292.         return;
  293.  
  294.     // players must join a team, if teamplay is on
  295.     if (teamplay && self.team_no == 0) 
  296.     {
  297.         // check for auto team placement
  298.         if (toggleflags & TFLAG_AUTOTEAM)
  299.         {
  300.             // If it failed, return
  301.             if (TeamFortress_TeamPutPlayerInTeam() == FALSE)
  302.                 return;
  303.         }
  304.         else
  305.         {
  306.             sprint(self, "You must join a team first. \n");
  307.             sprint(self, "use imin1, imin2, imin3, or imin4\n");
  308.             return;
  309.         }
  310.     }
  311.  
  312.     self.playerclass = self.impulse - TF_CHANGEPC;
  313.  
  314.     // Turn off PC_UNDEFINED's nomove and invincibility
  315.     self.takedamage = DAMAGE_AIM;
  316.     self.movetype = MOVETYPE_WALK;
  317.  
  318.     // give them a model, and a new spawn point
  319.     self.solid = SOLID_SLIDEBOX;
  320.     // pausetime is set by teleporters to keep the player from moving a while
  321.     self.pausetime = 0;
  322.     
  323.     spot = SelectSpawnPoint ();
  324.  
  325.     self.origin = spot.origin + '0 0 1';
  326.     self.angles = spot.angles;
  327.     self.fixangle = TRUE;        // turn this way immediately
  328.  
  329.     setmodel (self, "progs/eyes.mdl");
  330.     modelindex_eyes = self.modelindex;
  331.  
  332.     setmodel (self, "progs/player.mdl");
  333.     modelindex_player = self.modelindex;
  334.                                                
  335.     setsize (self, VEC_HULL_MIN, VEC_HULL_MAX);    
  336.     self.view_ofs = '0 0 22';
  337.     player_stand1 ();
  338.     if (deathmatch || coop)
  339.     {
  340.         makevectors(self.angles);
  341.         spawn_tfog (self.origin + v_forward*20);
  342.     }
  343.  
  344.     // Display chosen class, and Tell rest of the team in the future
  345.     if ( self.playerclass == PC_RANDOM )
  346.     {
  347.         sprint(self, "Random Playerclass.\n");
  348.         self.tfstate = (self.tfstate | TFSTATE_RANDOMPC);
  349.         self.playerclass = 1 + floor(random() * (PC_RANDOM - 1));
  350.     }
  351.  
  352.     TeamFortress_PrintClassName();
  353.     TeamFortress_SetEquipment();
  354.     TeamFortress_SetHealth();
  355.     TeamFortress_SetSpeed();
  356.     TeamFortress_SetSkin();
  357. };
  358.  
  359. //=========================================================================
  360. // Displays the player's inventory
  361. void() TeamFortress_Inventory =
  362. {
  363.     local entity tg;
  364.     local string ac;
  365.     local float col;
  366.  
  367.     // Display Team
  368.     sprint(self, "You're in team ");
  369.     ac = ftos(self.team_no);
  370.     sprint(self, ac);
  371.     sprint(self, ", color ");
  372.     col = TeamFortress_TeamGetColor(self.team_no);
  373.     ac = ftos(col);
  374.     sprint(self, ac);
  375.     sprint(self, ".\n");
  376.  
  377.     // Display Number of Grenades of each type
  378.     if (self.no_grenades_1 > 0)
  379.     {
  380.         sprint(self, "Gren.Type 1 : ");
  381.         if (self.tp_grenades_1 == GR_TYPE_NORMAL)
  382.             sprint(self, " Normal(");
  383.         if (self.tp_grenades_1 == GR_TYPE_CONCUSSION)
  384.             sprint(self, " Concussion(");
  385.         if (self.tp_grenades_1 == GR_TYPE_NAIL)
  386.             sprint(self, " Nail(");
  387.         if (self.tp_grenades_1 == GR_TYPE_MIRV)
  388.             sprint(self, " Mirv(");
  389.         ac = ftos(self.no_grenades_1);
  390.         sprint(self, ac);
  391.         sprint(self, ")\n");
  392.     }
  393.     if (self.no_grenades_2 > 0)
  394.     {
  395.         sprint(self, "Gren.Type 2 : ");
  396.         if (self.tp_grenades_2 == GR_TYPE_NORMAL)
  397.             sprint(self, " Normal(");
  398.         if (self.tp_grenades_2 == GR_TYPE_CONCUSSION)
  399.             sprint(self, " Concussion(");
  400.         if (self.tp_grenades_2 == GR_TYPE_NAIL)
  401.             sprint(self, " Nail(");
  402.         if (self.tp_grenades_2 == GR_TYPE_MIRV)
  403.             sprint(self, " Mirv(");
  404.         ac = ftos(self.no_grenades_1);
  405.         sprint(self, ac);
  406.         sprint(self, ")\n");
  407.     }
  408.  
  409.     // Scanner
  410.     if (self.tf_items & NIT_SCANNER)
  411.         sprint(self, "Scanner. ");
  412.  
  413.     // Medikit and ammo
  414.     if (self.secondary_items & NIT_MEDIKIT)
  415.     {
  416.         sprint(self, "Medikit (");
  417.         ac = ftos(self.ammo_medikit);
  418.         sprint(self, ac);
  419.         sprint(self,") ");
  420.     }
  421.  
  422.     // Detpack
  423.     if (self.secondary_items & NIT_DETPACK)
  424.     {
  425.         if (self.ammo_detpack > 0)
  426.         {
  427.             ac = ftos(self.ammo_detpack);
  428.             sprint(self, ac);
  429.             sprint(self, " Detpack");
  430.             if (self.ammo_detpack > 1)
  431.                 sprint(self, "s");
  432.             sprint(self, ". ");
  433.         }
  434.     }
  435.  
  436.     // GoalItems
  437.     tg = find (world, classname, "item_tfgoal");
  438.     while (tg)
  439.     {
  440.         if (tg.owner == self)
  441.         {
  442.             sprint(self, tg.netname);
  443.             sprint(self, ". ");
  444.         }
  445.  
  446.         tg = find(tg, classname, "item_tfgoal");
  447.     }
  448.  
  449.         
  450.     sprint(self, "\n");
  451. };
  452.  
  453. //=========================================================================
  454. // Displays the state of the ToggleFlags
  455. void() TeamFortress_ShowTF =
  456. {
  457.     local string st;
  458.  
  459.     // Classkin/Multiskin
  460.     if (toggleflags & TFLAG_SKIN)
  461.         sprint(self, "Multiskin On.\n");
  462.     else
  463.         sprint(self, "Classkin On.\n");
  464.  
  465.     // Class Persistence between lvls On/Off
  466.     if (toggleflags & TFLAG_CLASS_PERSIST)
  467.         sprint(self, "Class Persistence On.\n");
  468.     else
  469.         sprint(self, "Class Persistence Off.\n");
  470.  
  471.     // Cheat Checking On/Off
  472.     if (toggleflags & TFLAG_CHEATCHECK)
  473.         sprint(self, "Cheat Checking On.\n");
  474.     else
  475.         sprint(self, "Cheat Checking Off.\n");
  476.  
  477.     // FortressMap details On/Off    (see readme.txt for more info)
  478.     if (toggleflags & TFLAG_FORTRESSMAP)
  479.         sprint(self, "FortressMap On.\n");
  480.     else
  481.         sprint(self, "FortressMap Off.\n");
  482.  
  483.     // AutoTeam On/Off
  484.     if (toggleflags & TFLAG_AUTOTEAM)
  485.         sprint(self, "AutoTeam On.\n");
  486.     else
  487.         sprint(self, "AutoTeam Off.\n");
  488.  
  489.     // RespawnDelay
  490.     if ((toggleflags & TFLAG_RESPAWNDELAY) && (toggleflags & TFLAG_RESPAWNDELAY2))
  491.         st = ftos(TF_RESPAWNDELAY3);
  492.     else if (toggleflags & TFLAG_RESPAWNDELAY)
  493.         st = ftos(TF_RESPAWNDELAY1);
  494.     else if (toggleflags & TFLAG_RESPAWNDELAY2)
  495.         st = ftos(TF_RESPAWNDELAY2);
  496.     else
  497.         st = "No";
  498.     sprint(self, st);
  499.     if (st != "No")
  500.         sprint(self, " second");
  501.     sprint(self, " Respawn Delay.\n");
  502.  
  503. };
  504.  
  505. //=========================================================================
  506. // Primes a grenade of the type corresponding to the player's impulse
  507. void() TeamFortress_PrimeGrenade =
  508. {
  509.     local float gtype;
  510.     local string gs, ptime;
  511.     local entity tGrenade;
  512.  
  513.     // If you've already primed a grenade, return
  514.     if (self.tfstate & TFSTATE_GRENPRIMED)
  515.         return;
  516.  
  517.     if (self.impulse == TF_GRENADE_1)
  518.     {
  519.         gtype = self.tp_grenades_1;
  520.         if (self.tp_grenades_1 == GR_TYPE_CONCUSSION)
  521.             gs = "Concussion grenade";
  522.         else if (self.tp_grenades_1 == GR_TYPE_NAIL)
  523.             gs = "Nail grenade";
  524.         else if (self.tp_grenades_1 == GR_TYPE_MIRV)
  525.             gs = "Mirv grenade";
  526.         else
  527.             gs = "Grenade";
  528.  
  529.         if (self.no_grenades_1 > 0)
  530.         {
  531.             ptime = ftos( GR_PRIMETIME );
  532.             sprint(self, gs);
  533.             sprint(self, " primed, ");
  534.             sprint(self, ptime);
  535.             sprint(self, " seconds...\n");
  536.             self.no_grenades_1 = self.no_grenades_1 - 1;
  537.         }
  538.         else
  539.         {
  540.             sprint(self, "No ");
  541.             sprint(self, gs);
  542.             sprint(self, "s left.\n");
  543.             return;
  544.         }
  545.     }
  546.     if (self.impulse == TF_GRENADE_2)
  547.     {
  548.         gtype = self.tp_grenades_2;
  549.         if (self.tp_grenades_2 == GR_TYPE_CONCUSSION)
  550.             gs = "Concussion grenade";
  551.         else if (self.tp_grenades_2 == GR_TYPE_NAIL)
  552.             gs = "Nail grenade";
  553.         else if (self.tp_grenades_2 == GR_TYPE_MIRV)
  554.             gs = "Mirv grenade";
  555.         else
  556.             gs = "Grenade";
  557.  
  558.         if (self.no_grenades_2 > 0)
  559.         {
  560.             ptime = ftos( GR_PRIMETIME );
  561.             sprint(self, gs);
  562.             sprint(self, " primed, ");
  563.             sprint(self, ptime);
  564.             sprint(self, " seconds...\n");
  565.             self.no_grenades_2 = self.no_grenades_2 - 1;
  566.         }
  567.         else
  568.         {
  569.             sprint(self, "No ");
  570.             sprint(self, gs);
  571.             sprint(self, "s left.\n");
  572.             return;
  573.         }
  574.     }
  575.  
  576.     self.tfstate = (self.tfstate | TFSTATE_GRENPRIMED);
  577.     tGrenade = spawn();
  578.     tGrenade.owner = self;
  579.     tGrenade.weapon = gtype;
  580.     tGrenade.classname = "timer";
  581.     tGrenade.nextthink = time + GR_PRIMETIME;
  582.     tGrenade.think = TeamFortress_ExplodePerson;
  583. };
  584.  
  585. //=========================================================================
  586. // Throws a currently primed grenade
  587. void() TeamFortress_ThrowGrenade =
  588. {
  589.     local    entity missile, te;
  590.  
  591.     // If no grenade is primed, return
  592.     if (!(self.tfstate & TFSTATE_GRENPRIMED))
  593.         return;
  594.  
  595.     self.tfstate = self.tfstate - (self.tfstate & TFSTATE_GRENPRIMED);
  596.  
  597.     sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  598.  
  599.     self.punchangle_x = -2;
  600.  
  601.     missile = spawn ();
  602.     missile.owner = self;
  603.     missile.movetype = MOVETYPE_BOUNCE;
  604.     missile.solid = SOLID_BBOX;
  605.     missile.classname = "grenade";
  606.         
  607.     // set grenade speed
  608.  
  609.     makevectors (self.v_angle);
  610.  
  611.     if (self.v_angle_x)
  612.         missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  613.     else
  614.     {
  615.         missile.velocity = aim(self, 10000);
  616.         missile.velocity = missile.velocity * 600;
  617.         missile.velocity_z = 200;
  618.     }
  619.  
  620.     missile.avelocity = '300 300 300';
  621.  
  622.     missile.angles = vectoangles(missile.velocity);
  623.  
  624.     // set the grenade's alternative kill flag
  625.     missile.tfstate = missile.tfstate | TFSTATE_ALTKILL;
  626.  
  627.     // Find the grenade entity
  628.     te = find(world, classname, "timer");
  629.     while ((te.owner != self) || (te.think != TeamFortress_ExplodePerson))
  630.         te = find(te, classname, "timer");
  631.  
  632.     // If we haven't found the grenade, something's wrong
  633.     if (te == world)
  634.     {
  635.         dprint("Error! Grenade entity not found.\n");
  636.         return;
  637.     }
  638.  
  639.     // set the grenade's thinktime to when the PRIMETIME runs out
  640.     missile.nextthink = te.nextthink;
  641.  
  642.     // set the think and touches to the appropriate grenade type
  643.     if (te.weapon == GR_TYPE_NORMAL)
  644.     {
  645.         missile.touch = NormalGrenadeTouch;
  646.         missile.think = NormalGrenadeExplode;
  647.         missile.altkillweapon = AK_GRENADE;
  648.     }
  649.     if (te.weapon == GR_TYPE_CONCUSSION)
  650.     {
  651.         missile.touch = ConcussionGrenadeTouch;
  652.         missile.think = ConcussionGrenadeExplode;
  653.     }
  654.     if (te.weapon == GR_TYPE_NAIL)
  655.     {
  656.         missile.touch = NailGrenadeTouch;
  657.         missile.think = NailGrenadeExplode;
  658.         missile.altkillweapon = AK_GRENADE_NAIL;
  659.     }
  660.     if (te.weapon == GR_TYPE_MIRV)
  661.     {
  662.         missile.touch = MirvGrenadeTouch;
  663.         missile.think = MirvGrenadeExplode;
  664.         missile.altkillweapon = AK_GRENADE_MIRV;
  665.     }
  666.  
  667.     setmodel (missile, "progs/grenade.mdl");
  668.     setsize (missile, '0 0 0', '0 0 0');        
  669.     setorigin (missile, self.origin);
  670.  
  671. // Remove primed grenade object    
  672.     remove(te);
  673. };
  674.  
  675. //=========================================================================
  676. // PLAYER CLASS HANDLING FUNCTIONS
  677. //=========================================================================
  678. //=========================================================================
  679. // Alter the player's Movement based on class
  680. void() TeamFortress_SetSpeed =
  681. {
  682.     local string sp;
  683.     local float tf;
  684.  
  685.     stuffcmd(self,"v_idlescale 0\n");
  686.     stuffcmd(self,"cl_movespeedkey 1\n");
  687.  
  688.     if ( self.playerclass == PC_SCOUT )
  689.     {
  690.         self.maxfbspeed = PC_SCOUT_MAXSPEED;
  691.         self.maxstrafespeed = PC_SCOUT_MAXSTRAFESPEED;
  692.     }
  693.     else if ( self.playerclass == PC_SNIPER )
  694.     {
  695.         self.maxfbspeed = PC_SNIPER_MAXSPEED;
  696.         self.maxstrafespeed = PC_SNIPER_MAXSTRAFESPEED;
  697.     }
  698.     else if ( self.playerclass == PC_SOLDIER )
  699.     {
  700.         self.maxfbspeed = PC_SOLDIER_MAXSPEED;
  701.         self.maxstrafespeed = PC_SOLDIER_MAXSTRAFESPEED;
  702.     }
  703.     else if ( self.playerclass == PC_DEMOMAN )
  704.     {
  705.         self.maxfbspeed = PC_DEMOMAN_MAXSPEED;
  706.         self.maxstrafespeed = PC_DEMOMAN_MAXSTRAFESPEED;
  707.     }
  708.     else if ( self.playerclass == PC_MEDIC )
  709.     {
  710.         self.maxfbspeed = PC_MEDIC_MAXSPEED;
  711.         self.maxstrafespeed = PC_MEDIC_MAXSTRAFESPEED;
  712.     }
  713.     else if ( self.playerclass == PC_HVYWEAP )
  714.     {
  715.         self.maxfbspeed = PC_HVYWEAP_MAXSPEED;
  716.         self.maxstrafespeed = PC_HVYWEAP_MAXSTRAFESPEED;
  717.     }
  718.     else if ( self.playerclass == PC_UNDEFINED )
  719.     {
  720.         self.maxfbspeed = 50;
  721.         self.maxstrafespeed = 50;
  722.         self.movetype = MOVETYPE_NONE;
  723.     }
  724.  
  725.     sp = ftos(self.maxfbspeed);
  726.     stuffcmd(self,"cl_backspeed ");
  727.     stuffcmd(self,sp);
  728.     stuffcmd(self,"\n");
  729.     stuffcmd(self,"cl_forwardspeed ");
  730.     stuffcmd(self,sp);
  731.     stuffcmd(self,"\n");
  732.     sp = ftos(self.maxstrafespeed);
  733.     stuffcmd(self,"cl_sidespeed ");
  734.     stuffcmd(self,sp);
  735.     stuffcmd(self,"\n");
  736. };
  737.  
  738. //=========================================================================
  739. // Set the max_health of a player based on his/her class
  740. void() TeamFortress_SetHealth = 
  741. {
  742.     if ( self.playerclass == PC_SCOUT )
  743.         self.max_health = PC_SCOUT_MAXHEALTH;
  744.     else if ( self.playerclass == PC_SNIPER )
  745.         self.max_health = PC_SNIPER_MAXHEALTH;
  746.     else if ( self.playerclass == PC_SOLDIER )
  747.         self.max_health = PC_SOLDIER_MAXHEALTH;
  748.     else if ( self.playerclass == PC_DEMOMAN )
  749.         self.max_health = PC_DEMOMAN_MAXHEALTH;
  750.     else if ( self.playerclass == PC_MEDIC )
  751.         self.max_health = PC_MEDIC_MAXHEALTH;
  752.     else if ( self.playerclass == PC_HVYWEAP )
  753.         self.max_health = PC_HVYWEAP_MAXHEALTH;
  754.     else if ( self.playerclass == PC_UNDEFINED )
  755.     {
  756.         self.max_health = 1; 
  757.         self.takedamage = 0; // Prevent damage to PC_UNDEFINED players
  758.     }
  759.  
  760.     self.health = self.max_health;
  761. };
  762.  
  763. //=========================================================================
  764. // Set the skin of a player based on his/her class, if Classkin is on
  765. void() TeamFortress_SetSkin = 
  766. {
  767.     local string st;
  768.  
  769.     // If Multiskin is on, return
  770.     if (toggleflags & TFLAG_SKIN)
  771.         return;
  772.  
  773.     if ( self.playerclass == PC_SCOUT )
  774.         self.skin = PC_SCOUT_SKIN;
  775.     else if ( self.playerclass == PC_SNIPER )
  776.         self.skin = PC_SNIPER_SKIN;
  777.     else if ( self.playerclass == PC_SOLDIER )
  778.         self.skin = PC_SOLDIER_SKIN;
  779.     else if ( self.playerclass == PC_DEMOMAN )
  780.         self.skin = PC_DEMOMAN_SKIN;
  781.     else if ( self.playerclass == PC_MEDIC )
  782.         self.skin = PC_MEDIC_SKIN;
  783.     else if ( self.playerclass == PC_HVYWEAP )
  784.         self.skin = PC_HVYWEAP_SKIN;
  785.     else if ( self.playerclass == PC_UNDEFINED )
  786.         self.skin = 1;
  787.  
  788. };
  789.  
  790. //=========================================================================
  791. // Set the details of a player based on his/her class
  792. void() TeamFortress_SetEquipment =
  793. {
  794.     local entity te;
  795.  
  796.     if (self.classname != "player")
  797.         return;
  798.  
  799.     self.items = 0;
  800.     self.secondary_weapon = 0;
  801.     self.secondary_items = 0;
  802.     self.tf_items = 0;
  803.     self.tf_items_flags = 0;
  804.     self.armorclass = 0;
  805.     self.impulse = 0;
  806.  
  807.     self.ammo_medikit = 0;
  808.     self.maxammo_medikit = 0;
  809.     self.ammo_detpack = 0;
  810.     self.maxammo_detpack = 0;
  811.     self.items_allowed = 0;
  812.     self.secondary_items_allowed = 0;
  813.        self.armor_allowed = 0;
  814.        self.maxarmor = 0;
  815.     self.weaponmode = 0;
  816.     self.altkillweapon = 0;
  817.     self.heat = 0;
  818.     self.tfstate = self.tfstate - (self.tfstate & TFSTATE_RELOADING);
  819.  
  820.     // Start the Cheat-Checking Cyclic Event if CheatChecking Toggleflag is on
  821.     if (toggleflags & TFLAG_CHEATCHECK)
  822.     {
  823.         te = spawn();
  824.         te.nextthink = time + 20;
  825.         te.think = TeamFortress_CheckforCheats;
  826.         te.owner = self;
  827.         te.classname = "timer";
  828.     }
  829.  
  830.     if ( self.playerclass == PC_SCOUT )
  831.     {
  832.         self.items = self.items | PC_SCOUT_WEAPONS;
  833.         self.ammo_rockets = PC_SCOUT_INITAMMO_ROCKET;
  834.         self.ammo_nails = PC_SCOUT_INITAMMO_NAIL;
  835.         self.ammo_shells = PC_SCOUT_INITAMMO_SHOT;
  836.         self.ammo_cells = PC_SCOUT_INITAMMO_CELL;
  837.         self.maxammo_rockets = PC_SCOUT_MAXAMMO_ROCKET;
  838.         self.maxammo_nails = PC_SCOUT_MAXAMMO_NAIL;
  839.         self.maxammo_shells = PC_SCOUT_MAXAMMO_SHOT;
  840.         self.maxammo_cells = PC_SCOUT_MAXAMMO_CELL;
  841.  
  842.         self.no_grenades_1 = PC_SCOUT_GRENADE_INIT_1;
  843.         self.no_grenades_2 = PC_SCOUT_GRENADE_INIT_2;
  844.         self.tp_grenades_1 = PC_SCOUT_GRENADE_TYPE_1;
  845.         self.tp_grenades_2 = PC_SCOUT_GRENADE_TYPE_2;
  846.         self.tf_items = PC_SCOUT_TF_ITEMS;
  847.  
  848.         // the scanner defaults to enemy scanning ON, friendly scanning OFF
  849.         // and movement scanner only OFF
  850.         self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_ENEMY;
  851.  
  852.         self.armorclass = self.armorclass | PC_SCOUT_INITARMORCLASS;
  853.         self.armortype = PC_SCOUT_INITARMORTYPE;
  854.         self.armorvalue = PC_SCOUT_INITARMOR;
  855.            self.armor_allowed = PC_SCOUT_MAXARMORTYPE;
  856.            self.maxarmor = PC_SCOUT_MAXARMOR;
  857.         self.weapon = IT_NAILGUN;
  858.  
  859.         self.items_allowed = PC_SCOUT_WEAPONS;
  860.     }
  861.     else if ( self.playerclass == PC_SNIPER )
  862.     {
  863.         self.items = self.items | PC_SNIPER_WEAPONS;
  864.         self.ammo_rockets = PC_SNIPER_INITAMMO_ROCKET;
  865.         self.ammo_nails = PC_SNIPER_INITAMMO_NAIL;
  866.         self.ammo_shells = PC_SNIPER_INITAMMO_SHOT;
  867.         self.ammo_cells = PC_SNIPER_INITAMMO_CELL;
  868.         self.maxammo_rockets = PC_SNIPER_MAXAMMO_ROCKET;
  869.         self.maxammo_nails = PC_SNIPER_MAXAMMO_NAIL;
  870.         self.maxammo_shells = PC_SNIPER_MAXAMMO_SHOT;
  871.         self.maxammo_cells = PC_SNIPER_MAXAMMO_CELL;
  872.     
  873.         self.no_grenades_1 = PC_SNIPER_GRENADE_INIT_1;
  874.         self.no_grenades_2 = PC_SNIPER_GRENADE_INIT_2;
  875.         self.tp_grenades_1 = PC_SNIPER_GRENADE_TYPE_1;
  876.         self.tp_grenades_2 = PC_SNIPER_GRENADE_TYPE_2;
  877.         self.tf_items = PC_SNIPER_TF_ITEMS;
  878.  
  879.         // Get the sniper's weapon
  880.         self.secondary_items = self.secondary_items | NIT_SNIPER_RIFLE | NIT_AUTO_RIFLE;
  881.  
  882.         self.armorclass = self.armorclass | PC_SNIPER_INITARMORCLASS;
  883.         self.armortype = PC_SNIPER_INITARMORTYPE;
  884.         self.armorvalue = PC_SNIPER_INITARMOR;
  885.            self.armor_allowed = PC_SNIPER_MAXARMORTYPE;
  886.            self.maxarmor = PC_SNIPER_MAXARMOR;
  887.         self.weapon = IT_EXTRA_WEAPON;
  888.         self.secondary_weapon = NIT_SNIPER_RIFLE;
  889.  
  890.         self.items_allowed = PC_SNIPER_WEAPONS;
  891.     }
  892.     else if ( self.playerclass == PC_SOLDIER )
  893.     {
  894.         self.items = self.items | PC_SOLDIER_WEAPONS;
  895.         self.ammo_rockets = PC_SOLDIER_INITAMMO_ROCKET;
  896.         self.ammo_nails = PC_SOLDIER_INITAMMO_NAIL;
  897.         self.ammo_shells = PC_SOLDIER_INITAMMO_SHOT;
  898.         self.ammo_cells = PC_SOLDIER_INITAMMO_CELL;
  899.         self.maxammo_rockets = PC_SOLDIER_MAXAMMO_ROCKET;
  900.         self.maxammo_nails = PC_SOLDIER_MAXAMMO_NAIL;
  901.         self.maxammo_shells = PC_SOLDIER_MAXAMMO_SHOT;
  902.         self.maxammo_cells = PC_SOLDIER_MAXAMMO_CELL;
  903.     
  904.         self.no_grenades_1 = PC_SOLDIER_GRENADE_INIT_1;
  905.         self.no_grenades_2 = PC_SOLDIER_GRENADE_INIT_2;
  906.         self.tp_grenades_1 = PC_SOLDIER_GRENADE_TYPE_1;
  907.         self.tp_grenades_2 = PC_SOLDIER_GRENADE_TYPE_2;
  908.         self.tf_items = PC_SOLDIER_TF_ITEMS;
  909.  
  910.         self.armorclass = self.armorclass | PC_SOLDIER_INITARMORCLASS;
  911.         self.armortype = PC_SOLDIER_INITARMORTYPE;
  912.         self.armorvalue = PC_SOLDIER_INITARMOR;
  913.            self.armor_allowed = PC_SOLDIER_MAXARMORTYPE;
  914.            self.maxarmor = PC_SOLDIER_MAXARMOR;
  915.         self.weapon = IT_ROCKET_LAUNCHER;
  916.  
  917.         self.items_allowed = PC_SOLDIER_WEAPONS;
  918.     }
  919.     else if ( self.playerclass == PC_DEMOMAN )
  920.     {
  921.         self.items = self.items | PC_DEMOMAN_WEAPONS;
  922.         self.ammo_rockets = PC_DEMOMAN_INITAMMO_ROCKET;
  923.         self.ammo_nails = PC_DEMOMAN_INITAMMO_NAIL;
  924.         self.ammo_shells = PC_DEMOMAN_INITAMMO_SHOT;
  925.         self.ammo_cells = PC_DEMOMAN_INITAMMO_CELL;
  926.         self.maxammo_rockets = PC_DEMOMAN_MAXAMMO_ROCKET;
  927.         self.maxammo_nails = PC_DEMOMAN_MAXAMMO_NAIL;
  928.         self.maxammo_shells = PC_DEMOMAN_MAXAMMO_SHOT;
  929.         self.maxammo_cells = PC_DEMOMAN_MAXAMMO_CELL;
  930.     
  931.         self.no_grenades_1 = PC_DEMOMAN_GRENADE_INIT_1;
  932.         self.no_grenades_2 = PC_DEMOMAN_GRENADE_INIT_2;
  933.         self.tp_grenades_1 = PC_DEMOMAN_GRENADE_TYPE_1;
  934.         self.tp_grenades_2 = PC_DEMOMAN_GRENADE_TYPE_2;
  935.         self.tf_items = PC_DEMOMAN_TF_ITEMS;
  936.  
  937.         // Detpacks
  938.         self.secondary_items = self.secondary_items | NIT_DETPACK;
  939.         self.ammo_detpack = PC_DEMOMAN_INITAMMO_DETPACK;
  940.         self.maxammo_detpack = PC_DEMOMAN_MAXAMMO_DETPACK;
  941.  
  942.         self.armorclass = self.armorclass | PC_DEMOMAN_INITARMORCLASS;
  943.         self.armortype = PC_DEMOMAN_INITARMORTYPE;
  944.         self.armorvalue = PC_DEMOMAN_INITARMOR;
  945.            self.armor_allowed = PC_DEMOMAN_MAXARMORTYPE;
  946.            self.maxarmor = PC_DEMOMAN_MAXARMOR;
  947.         self.weapon = IT_GRENADE_LAUNCHER;
  948.  
  949.         self.items_allowed = PC_DEMOMAN_WEAPONS;
  950.     }
  951.     else if ( self.playerclass == PC_MEDIC )
  952.     {
  953.         self.items = self.items | PC_MEDIC_WEAPONS;
  954.         self.ammo_rockets = PC_MEDIC_INITAMMO_ROCKET;
  955.         self.ammo_nails = PC_MEDIC_INITAMMO_NAIL;
  956.         self.ammo_shells = PC_MEDIC_INITAMMO_SHOT;
  957.         self.ammo_cells = PC_MEDIC_INITAMMO_CELL;
  958.         self.maxammo_rockets = PC_MEDIC_MAXAMMO_ROCKET;
  959.         self.maxammo_nails = PC_MEDIC_MAXAMMO_NAIL;
  960.         self.maxammo_shells = PC_MEDIC_MAXAMMO_SHOT;
  961.         self.maxammo_cells = PC_MEDIC_MAXAMMO_CELL;
  962.     
  963.         self.no_grenades_1 = PC_MEDIC_GRENADE_INIT_1;
  964.         self.no_grenades_2 = PC_MEDIC_GRENADE_INIT_2;
  965.         self.tp_grenades_1 = PC_MEDIC_GRENADE_TYPE_1;
  966.         self.tp_grenades_2 = PC_MEDIC_GRENADE_TYPE_2;
  967.         self.tf_items = PC_MEDIC_TF_ITEMS;
  968.  
  969.         self.armorclass = self.armorclass | PC_MEDIC_INITARMORCLASS;
  970.         self.armortype = PC_MEDIC_INITARMORTYPE;
  971.         self.armorvalue = PC_MEDIC_INITARMOR;
  972.            self.armor_allowed = PC_MEDIC_MAXARMORTYPE;
  973.            self.maxarmor = PC_MEDIC_MAXARMOR;
  974.         self.weapon = IT_SUPER_NAILGUN;
  975.  
  976.         // BioWeapon
  977.         self.secondary_items = self.secondary_items | NIT_BIOWEAPON;
  978.         // Medikit
  979.         self.secondary_items = self.secondary_items | NIT_MEDIKIT;
  980.         self.ammo_medikit = PC_MEDIC_INITAMMO_MEDIKIT;
  981.         self.maxammo_medikit = PC_MEDIC_MAXAMMO_MEDIKIT;
  982.  
  983.         // Start the Regeneration Cyclic Event
  984.         te = spawn();
  985.         te.nextthink = time + PC_MEDIC_REGEN_TIME;
  986.         te.think = TeamFortress_Regenerate;
  987.         te.owner = self;
  988.         te.classname = "timer";
  989.  
  990.         self.items_allowed = PC_MEDIC_WEAPONS;
  991.     }
  992.     else if ( self.playerclass == PC_HVYWEAP )
  993.     {
  994.         self.items = self.items | PC_HVYWEAP_WEAPONS;
  995.         self.ammo_rockets = PC_HVYWEAP_INITAMMO_ROCKET;
  996.         self.ammo_nails = PC_HVYWEAP_INITAMMO_NAIL;
  997.         self.ammo_shells = PC_HVYWEAP_INITAMMO_SHOT;
  998.         self.ammo_cells = PC_HVYWEAP_INITAMMO_CELL;
  999.         self.maxammo_rockets = PC_HVYWEAP_MAXAMMO_ROCKET;
  1000.         self.maxammo_nails = PC_HVYWEAP_MAXAMMO_NAIL;
  1001.         self.maxammo_shells = PC_HVYWEAP_MAXAMMO_SHOT;
  1002.         self.maxammo_cells = PC_HVYWEAP_MAXAMMO_CELL;
  1003.     
  1004.         self.no_grenades_1 = PC_HVYWEAP_GRENADE_INIT_1;
  1005.         self.no_grenades_2 = PC_HVYWEAP_GRENADE_INIT_2;
  1006.         self.tp_grenades_1 = PC_HVYWEAP_GRENADE_TYPE_1;
  1007.         self.tp_grenades_2 = PC_HVYWEAP_GRENADE_TYPE_2;
  1008.         self.tf_items = PC_HVYWEAP_TF_ITEMS;
  1009.  
  1010.         // Get the Assault Cannon
  1011.         self.secondary_items = self.secondary_items | NIT_ASSAULT_CANNON;
  1012.  
  1013.         self.armorclass = self.armorclass | PC_HVYWEAP_INITARMORCLASS;
  1014.         self.armortype = PC_HVYWEAP_INITARMORTYPE;
  1015.         self.armorvalue = PC_HVYWEAP_INITARMOR;
  1016.            self.armor_allowed = PC_HVYWEAP_MAXARMORTYPE;
  1017.            self.maxarmor = PC_HVYWEAP_MAXARMOR;
  1018.         self.weapon = IT_NAILGUN;
  1019.  
  1020.         self.items_allowed = PC_HVYWEAP_WEAPONS;
  1021.     }
  1022.     else if ( self.playerclass == PC_UNDEFINED )
  1023.     {
  1024.         self.items = 0;
  1025.         self.ammo_rockets = 0;
  1026.         self.ammo_nails = 0;
  1027.         self.ammo_shells = 0;
  1028.         self.ammo_cells = 0;
  1029.  
  1030.         self.no_grenades_1 = 0;
  1031.         self.no_grenades_2 = 0;
  1032.         self.tp_grenades_1 = 0;
  1033.         self.tp_grenades_2 = 0;
  1034.     
  1035.         self.armorclass = 0;
  1036.         self.armortype = 0;
  1037.         self.armorvalue = 0;
  1038.         self.weapon = 0;
  1039.  
  1040.         self.movetype = MOVETYPE_NONE;
  1041.         self.solid = SOLID_NOT;
  1042.         self.model = "";
  1043.         self.mdl = "";
  1044.         self.modelindex = 0;
  1045.         modelindex_player = 0;
  1046.         self.deadflag = DEAD_DEAD;
  1047.         self.tfstate = self.tfstate | TFSTATE_RELOADING;
  1048.     
  1049.         setmodel(self, "");
  1050.     }
  1051.  
  1052.     W_SetCurrentAmmo ();
  1053. };
  1054.  
  1055. //=========================================================================
  1056. // Return the max amount of ammo the Retriever can carry, based on his class
  1057. float(entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo =
  1058. {
  1059.     if (AmmoType == IT_SHELLS)
  1060.     {
  1061.         return Retriever.maxammo_shells;
  1062.     }
  1063.     else if (AmmoType == IT_NAILS)
  1064.     {
  1065.         return Retriever.maxammo_nails;
  1066.     }
  1067.     else if (AmmoType == IT_CELLS)
  1068.     {
  1069.         return Retriever.maxammo_cells;
  1070.     }
  1071.     else if (AmmoType == IT_ROCKETS)
  1072.     {
  1073.         return Retriever.maxammo_rockets;
  1074.     }
  1075.     else if (AmmoType == NIT_MEDIKIT)
  1076.     {
  1077.         return Retriever.maxammo_medikit;
  1078.     }
  1079.     else if (AmmoType == NIT_DETPACK)
  1080.     {
  1081.         return Retriever.maxammo_detpack;
  1082.     }
  1083.  
  1084.     dprint("Error in TeamFortress_GetMaxAmmo()\n");
  1085.     dprint("Invalid ammo type passed.\n");
  1086.     return 0;
  1087. };
  1088.  
  1089. //=========================================================================
  1090. // Return 1 if the Retriever is allowed to pick up the Weapon
  1091. float(entity Retriever, float WeaponType) TeamFortress_CanGetWeapon =
  1092. {
  1093.     if ( Retriever.items_allowed & WeaponType )
  1094.         return 1;
  1095.  
  1096.     return 0;
  1097. };
  1098.  
  1099. //=========================================================================
  1100. // Return 1 if the Retriever is allowed to pick up the Armor
  1101. float(entity Retriever, entity Armor) TeamFortress_CanGetArmor =
  1102. {
  1103.     local float    type;
  1104.     local float af;
  1105.     local string at;
  1106.  
  1107.     if (Armor.classname == "item_armor1")
  1108.     {
  1109.         type = 0.3;
  1110.     }
  1111.     else if (Armor.classname == "item_armor2")
  1112.     {
  1113.         type = 0.6;
  1114.     }
  1115.     else if (Armor.classname == "item_armorInv")
  1116.     {
  1117.         type = 0.8;
  1118.     }
  1119.     else
  1120.     {
  1121.         dprint("Error in TeamFortress_CanGetArmor()\n");
  1122.         dprint("Invalid armor type passed.\n");
  1123.         return 0;
  1124.     }
  1125.  
  1126.     // af = Armor.spawnflags - (Armor.spawnflags & AT_NORMAL);
  1127.  
  1128.     if ( type > Retriever.armor_allowed )
  1129.         return 0;
  1130.  
  1131.     return 1;
  1132.  
  1133. //    if (!af)
  1134. //        return 1;
  1135. //    if (PC_SCOUT_ARMORCLASSES & af)
  1136. //        return 1;
  1137.  
  1138.     return 0;
  1139. };
  1140.  
  1141.  
  1142. //=========================================================================
  1143. // Controls the equipment a class receives from backpacks
  1144. float(entity Retriever, entity Items) TeamFortress_AddBackpackItems =
  1145. {
  1146.     // If you want the classes to _not_ start off with all their legal
  1147.     // weapons, then you may want them to be able to pick up weapons
  1148.     // from backpacks. If so, this is where to do it.
  1149.     // For now, return. 
  1150.     return;
  1151. };
  1152.  
  1153. //=========================================================================
  1154. // Display the name of the playerclass
  1155. void() TeamFortress_PrintClassName =
  1156. {
  1157.     local string st;
  1158.  
  1159.     if ( self.playerclass == PC_SCOUT )
  1160.         sprint(self, "Scout ");
  1161.     else if ( self.playerclass == PC_SNIPER )
  1162.         sprint(self, "Sniper ");
  1163.     else if ( self.playerclass == PC_SOLDIER )
  1164.         sprint(self, "Soldier ");
  1165.     else if ( self.playerclass == PC_DEMOMAN )
  1166.         sprint(self, "Demolitions Man ");
  1167.     else if ( self.playerclass == PC_MEDIC )
  1168.         sprint(self, "Combat Medic ");
  1169.     else if ( self.playerclass == PC_HVYWEAP )
  1170.         sprint(self, "Heavy Weapons Guy ");
  1171.     else if ( self.playerclass == PC_UNDEFINED )
  1172.         sprint(self, "Undefined ");
  1173.     else
  1174.     {
  1175.         sprint(self, "Error! Impossible Playerclass : ");
  1176.         st = ftos(self.playerclass);
  1177.         sprint(self, st);
  1178.         sprint(self, "\n");
  1179.         return;
  1180.     }
  1181.  
  1182.     if ( self.tfstate & TFSTATE_RANDOMPC)
  1183.         sprint(self, "(Random)");
  1184.     sprint(self, "\n");
  1185. };
  1186.  
  1187. //=========================================================================
  1188. // Remove all the timers for this player
  1189. void() TeamFortress_RemoveTimers =
  1190. {
  1191.     local entity te;
  1192.  
  1193.     // Remove all the timer entities for this player
  1194.     te = find(world, classname, "timer");
  1195.     while (te != world)
  1196.     {
  1197.         if (te.owner == self)
  1198.         {
  1199.             remove(te);
  1200.             te = find(world, classname, "timer");
  1201.         }
  1202.         else
  1203.             te = find(te, classname, "timer");
  1204.     }
  1205.  
  1206.     // Drop any GoalItems
  1207.     te = find (world, classname, "item_tfgoal");
  1208.     while (te)
  1209.     {
  1210.         if (te.owner == self)
  1211.         {
  1212.             // Remove it from the player
  1213.             tfgoalitem_RemoveFromAP(te, self, 0);
  1214.         }
  1215.         te = find(te, classname, "item_tfgoal");
  1216.     }
  1217.  
  1218.     stuffcmd(self, "v_idlescale 0\n");
  1219. };
  1220.  
  1221. //=========================================================================
  1222. // Check all stats to make sure they're good for this class
  1223. void() TeamFortress_CheckClassStats =
  1224. {
  1225.     // Check armor
  1226.     if (self.armortype > self.armor_allowed)
  1227.         self.armortype = self.armor_allowed;
  1228.     if (self.armorvalue > self.maxarmor)
  1229.         self.armorvalue = self.maxarmor;
  1230.     if (self.armortype < 0)
  1231.         self.armortype = 0;
  1232.     if (self.armorvalue < 0)
  1233.         self.armorvalue = 0;
  1234.     // Check ammo
  1235.     if (self.ammo_shells > TeamFortress_GetMaxAmmo(self,IT_SHELLS))
  1236.         self.ammo_shells = TeamFortress_GetMaxAmmo(self,IT_SHELLS);
  1237.     if (self.ammo_shells < 0)
  1238.         self.ammo_shells = 0;
  1239.     if (self.ammo_nails > TeamFortress_GetMaxAmmo(self,IT_NAILS))
  1240.         self.ammo_nails = TeamFortress_GetMaxAmmo(self,IT_NAILS);
  1241.     if (self.ammo_nails < 0)
  1242.         self.ammo_nails = 0;
  1243.     if (self.ammo_rockets > TeamFortress_GetMaxAmmo(self,IT_ROCKETS))
  1244.         self.ammo_rockets = TeamFortress_GetMaxAmmo(self,IT_ROCKETS);        
  1245.     if (self.ammo_rockets < 0)
  1246.         self.ammo_rockets = 0;
  1247.     if (self.ammo_cells > TeamFortress_GetMaxAmmo(self,IT_CELLS))
  1248.         self.ammo_cells = TeamFortress_GetMaxAmmo(self,IT_CELLS);        
  1249.     if (self.ammo_cells < 0)
  1250.         self.ammo_cells = 0;
  1251.     if (self.ammo_medikit > TeamFortress_GetMaxAmmo(self,NIT_MEDIKIT))
  1252.         self.ammo_medikit = TeamFortress_GetMaxAmmo(self,NIT_MEDIKIT);        
  1253.     if (self.ammo_medikit < 0)
  1254.         self.ammo_medikit = 0;
  1255.     if (self.ammo_detpack > TeamFortress_GetMaxAmmo(self,NIT_DETPACK))
  1256.         self.ammo_detpack = TeamFortress_GetMaxAmmo(self,NIT_DETPACK);        
  1257.     if (self.ammo_detpack < 0)
  1258.         self.ammo_detpack = 0;
  1259.     // Check Grenades
  1260.     if (self.no_grenades_1 < 0)
  1261.         self.no_grenades_1 = 0;
  1262.     if (self.no_grenades_2 < 0)
  1263.         self.no_grenades_2 = 0;
  1264.     // Check health
  1265.     if (self.health > self.max_health)
  1266.         self.health = self.max_health;
  1267.     if (self.health < 0)
  1268.         self.health = 0;
  1269. };
  1270.  
  1271. //=========================================================================
  1272. // WEAPON HANDLING FUNCTIONS
  1273. //=========================================================================
  1274. //=========================================================================
  1275. // Sniper/Auto Rifle selection function
  1276. void() TeamFortress_SniperWeapon =
  1277. {
  1278.     local    float    it;
  1279.     
  1280.     self.impulse = 0;
  1281.  
  1282.     if (self.tfstate & TFSTATE_RELOADING)
  1283.            return;
  1284.  
  1285.     if (!((self.secondary_items & NIT_SNIPER_RIFLE) && (self.secondary_items & NIT_AUTO_RIFLE)))
  1286.         return;
  1287.  
  1288.     if (self.ammo_shells < 1)
  1289.     {    // don't have the ammo
  1290.         sprint (self, "not enough ammo.\n");
  1291.         return;
  1292.     }
  1293.  
  1294.     if (self.weapon == IT_EXTRA_WEAPON && self.secondary_weapon == NIT_SNIPER_RIFLE)
  1295.     {
  1296.         self.secondary_weapon = NIT_AUTO_RIFLE;
  1297.     }
  1298.     else if (self.weapon == IT_EXTRA_WEAPON && self.secondary_weapon == NIT_AUTO_RIFLE)
  1299.     {
  1300.         self.secondary_weapon = NIT_SNIPER_RIFLE;
  1301.     }
  1302.     else
  1303.     {
  1304.         self.secondary_weapon = NIT_SNIPER_RIFLE;
  1305.         self.weapon = IT_EXTRA_WEAPON;
  1306.     }
  1307.  
  1308.     W_SetCurrentAmmo ();
  1309. };
  1310.  
  1311. //=========================================================================
  1312. // Assault Cannon selection function
  1313. void() TeamFortress_AssaultWeapon =
  1314. {
  1315.     local    float    it;
  1316.     
  1317.     self.impulse = 0;
  1318.  
  1319.     if (self.tfstate & TFSTATE_RELOADING)
  1320.            return;
  1321.  
  1322.     if (!(self.secondary_items & NIT_ASSAULT_CANNON)) 
  1323.         return;
  1324.  
  1325.     if (self.heat > 0)
  1326.     {
  1327.         sprint(self, "the assault cannon is still overheated.\n");
  1328.         return;
  1329.     }
  1330.  
  1331.     if (self.ammo_shells < 1)
  1332.     {    // don't have the ammo
  1333.         sprint (self, "not enough ammo.\n");
  1334.         return;
  1335.     }
  1336.     // The cannon also nees 10 cells to power up 
  1337.     if (self.ammo_cells < 10)
  1338.     {
  1339.         sprint(self, "not enough cells to power the assault cannon.\n");
  1340.         return;
  1341.     }
  1342.  
  1343.     self.secondary_weapon = NIT_ASSAULT_CANNON;
  1344.     self.weapon = IT_EXTRA_WEAPON;
  1345.  
  1346.     W_SetCurrentAmmo ();
  1347. };
  1348.  
  1349. //=========================================================================
  1350. // If this gets called, the players holding onto an exploding grenade :)
  1351. void() TeamFortress_ExplodePerson =
  1352. {
  1353.     local    entity missile;
  1354.  
  1355.     // Removes the owners grenade
  1356.     self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_GRENPRIMED);
  1357.  
  1358.     self.owner.punchangle_x = -2;
  1359.  
  1360.     missile = spawn ();
  1361.     missile.movetype = MOVETYPE_BOUNCE;
  1362.     missile.solid = SOLID_BBOX;
  1363.     missile.classname = "grenade";
  1364.         
  1365.     // Don't bother calculating a velocity
  1366.     missile.velocity = '0 0 0';
  1367.     missile.avelocity = '300 300 300';
  1368.  
  1369.     missile.angles = vectoangles(missile.velocity);
  1370.     
  1371.     // set the grenade's alternative kill flag
  1372.     missile.tfstate = missile.tfstate | TFSTATE_ALTKILL;
  1373.  
  1374.     // set the grenades thinktime to now
  1375.     missile.nextthink = time + 0.1;
  1376.  
  1377.     // set the think and touches to the appropriate grenade type
  1378.     if (self.weapon == GR_TYPE_NORMAL)
  1379.     {
  1380.         missile.touch = NormalGrenadeTouch;
  1381.         missile.think = NormalGrenadeExplode;
  1382.         missile.altkillweapon = AK_GRENADE;
  1383.     }
  1384.     if (self.weapon == GR_TYPE_CONCUSSION)
  1385.     {
  1386.         missile.touch = ConcussionGrenadeTouch;
  1387.         missile.think = ConcussionGrenadeExplode;
  1388.     }
  1389.     if (self.weapon == GR_TYPE_NAIL)
  1390.     {
  1391.         missile.touch = NailGrenadeTouch;
  1392.         missile.think = NailGrenadeExplode;
  1393.         missile.altkillweapon = AK_GRENADE_NAIL;
  1394.     }
  1395.     if (self.weapon == GR_TYPE_MIRV)
  1396.     {
  1397.         missile.touch = MirvGrenadeTouch;
  1398.         missile.think = MirvGrenadeExplode;
  1399.         missile.altkillweapon = AK_GRENADE_MIRV;
  1400.     }
  1401.  
  1402.     setmodel (missile, "progs/grenade.mdl");
  1403.     setsize (missile, '0 0 0', '0 0 0');        
  1404.     setorigin (missile, self.owner.origin);
  1405.  
  1406.     bprint("No ");
  1407.     bprint(self.owner.netname);
  1408.     bprint(", throw the grenade, not the pin!\n");
  1409.  
  1410. // Remove primed grenade object    
  1411.     remove(self);
  1412. };
  1413.  
  1414. //=========================================================================
  1415. // Touch function for a concussion grenade
  1416. void() ConcussionGrenadeTouch =
  1417. {
  1418.     if (other.takedamage == DAMAGE_AIM)
  1419.     {
  1420.         // A person hit by a concussion grenade doesn't move much,
  1421.         // since their origin is pretty much right on the grenade's
  1422.         // explosion point, so we'll give him a kick.
  1423.         other.velocity_x = self.velocity_x - 300;
  1424.         other.velocity_y = self.velocity_y - 300;
  1425.         other.velocity_z = 300;
  1426.  
  1427.         if (other.classname != "player")
  1428.         {
  1429.             if(other.flags & FL_ONGROUND)
  1430.                 other.flags = other.flags - FL_ONGROUND;
  1431.         }
  1432.  
  1433.         ConcussionGrenadeExplode();
  1434.         return;
  1435.     }
  1436.  
  1437.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);    // bounce sound
  1438.     if (self.velocity == '0 0 0')
  1439.         self.avelocity = '0 0 0';
  1440. };
  1441.  
  1442. //=========================================================================
  1443. // Concussion grenade explosion function
  1444. void() ConcussionGrenadeExplode =
  1445. {    
  1446.     T_RadiusBounce (self, self.owner, 240, world);
  1447.  
  1448.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1449.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  1450.     WriteCoord (MSG_BROADCAST, self.origin_x);
  1451.     WriteCoord (MSG_BROADCAST, self.origin_y);
  1452.     WriteCoord (MSG_BROADCAST, self.origin_z);
  1453.         
  1454.     BecomeExplosion ();
  1455. };
  1456.  
  1457. //=========================================================================
  1458. // Concussion grenade timer to remove idlescale
  1459. void() ConcussionGrenadeTimer =
  1460. {
  1461.     local string st;
  1462.  
  1463.     self.health = self.health - GR_CONCUSS_DEC;
  1464.     if (self.health < 0)
  1465.         self.health = 0;
  1466.     self.nextthink = time + GR_CONCUSS_TIME;
  1467.  
  1468.     st = ftos(self.health);
  1469.     stuffcmd(self.owner, "v_idlescale ");
  1470.     stuffcmd(self.owner, st);
  1471.     stuffcmd(self.owner, "\n");
  1472.  
  1473.     if (self.health == 0)
  1474.         remove(self);
  1475. };
  1476.  
  1477. //=========================================================================
  1478. // Touch Function for Nail Grenade
  1479. void() NailGrenadeTouch =
  1480. {
  1481.     if (other == self.owner)
  1482.         return;        // don't explode on owner
  1483.  
  1484.     // If the Nail Grenade hits a player, it just bounces off
  1485.  
  1486.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
  1487.     if (self.velocity == '0 0 0')
  1488.         self.avelocity = '0 0 0';
  1489. };
  1490.  
  1491. //=========================================================================
  1492. // Explode Function for Nail Grenade
  1493. void() NailGrenadeExplode =
  1494. {
  1495.     // Raise into the air
  1496.     self.movetype = MOVETYPE_NOCLIP;
  1497.     self.velocity = '0 0 100';
  1498.     self.avelocity = '0 500 0';
  1499.     self.nextthink = time + 0.5;
  1500.     self.think = NailGrenadeNailEm;
  1501. };
  1502.  
  1503. //=========================================================================
  1504. // Nail function for Nail Grenade
  1505. void() NailGrenadeNailEm =
  1506. {
  1507.     // Rotate and spew Nails
  1508.     self.velocity = '0 0 0';
  1509.  
  1510.     self.nextthink = time + 0.1;
  1511.     self.think = NailGrenadeLaunchNail;
  1512.     self.playerclass = 0;
  1513. };
  1514.  
  1515. //=========================================================================
  1516. // Nail function for Nail Grenade
  1517. void() NailGrenadeLaunchNail =
  1518. {
  1519.     local float i,j;
  1520.  
  1521.     i = 0;
  1522.     while (i < 3)
  1523.     {
  1524.         j = (random() + 2) * 2;
  1525.         current_yaw = anglemod( self.angles_y );
  1526.         current_yaw = anglemod(current_yaw + j);
  1527.         self.angles_y = current_yaw;
  1528.         self.angles_x = 0;
  1529.         self.angles_z = 0;
  1530.         makevectors(self.angles);
  1531.  
  1532.         launch_spike(self.origin, v_forward, 1, AK_GRENADE_NAIL);
  1533.  
  1534.         i = i + 1;
  1535.     }
  1536.  
  1537.     self.playerclass = self.playerclass + 1;
  1538.     self.nextthink = time + 0.1;
  1539.  
  1540.     // Explode 
  1541.     if (self.playerclass > 50)
  1542.         self.think = GrenadeExplode;
  1543. };
  1544.  
  1545. //=========================================================================
  1546. // Touch Function for Mirv Grenade
  1547. // Mirv Grenade heavily influenced by the Firewall Grenade by Steve Bond (wedge@nuc.net)
  1548. void() MirvGrenadeTouch =
  1549. {
  1550.     if (other == self.owner)
  1551.         return;        // don't explode on owner
  1552.  
  1553.     // If the Mirv Grenade hits a player, it just bounces off
  1554.  
  1555.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
  1556.     if (self.velocity == '0 0 0')
  1557.         self.avelocity = '0 0 0';
  1558. };
  1559.  
  1560. //=========================================================================
  1561. // Mirv Grenade explode function, for when the PRIMETIME runs out
  1562. void() MirvGrenadeExplode =
  1563. {
  1564.     local float i;
  1565.  
  1566.     T_RadiusDamage (self, self.owner, 250, world);
  1567.  
  1568.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1569.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  1570.     WriteCoord (MSG_BROADCAST, self.origin_x);
  1571.     WriteCoord (MSG_BROADCAST, self.origin_y);
  1572.     WriteCoord (MSG_BROADCAST, self.origin_z);
  1573.  
  1574.     self.solid=SOLID_NOT;
  1575.     BecomeExplosion ();
  1576.  
  1577.     // Launch mirvs
  1578.     i = 0;
  1579.     while (i < GR_TYPE_MIRV_NO)
  1580.     {
  1581.         MirvGrenadeLaunch (self.origin + '0 0 -1',self.owner);
  1582.         i = i + 1;
  1583.     }
  1584. };
  1585.  
  1586. //=========================================================================
  1587. // Launch a Mirv
  1588. void (vector org, entity shooter) MirvGrenadeLaunch =
  1589. {
  1590.     local float xdir,ydir,zdir, spin;
  1591.     
  1592.     xdir = 150 * random() - 75;
  1593.     ydir = 150 * random() - 75;
  1594.     zdir = 40 * random();
  1595.  
  1596.     newmis = spawn ();
  1597.     newmis.owner = shooter;
  1598.     newmis.movetype = MOVETYPE_BOUNCE;
  1599.     self.touch = SUB_Null;
  1600.     newmis.solid = SOLID_BBOX;
  1601.  
  1602.     newmis.classname = "grenade";
  1603.     newmis.touch = GrenadeTouch;
  1604.     newmis.think =     GrenadeExplode;
  1605.     newmis.nextthink = time + 2;
  1606.     
  1607.     newmis.velocity_x = xdir * 2;
  1608.     newmis.velocity_y = ydir * 2;
  1609.     newmis.velocity_z = zdir * 15;
  1610.  
  1611.     // Set ALTKILL
  1612.     newmis.tfstate = newmis.tfstate | TFSTATE_ALTKILL;
  1613.     newmis.altkillweapon = AK_GRENADE_MIRV;
  1614.  
  1615.     spin = (random() * 10) / 2;
  1616.     if (spin <= 0)
  1617.         newmis.avelocity='250 300 400';
  1618.     if (spin == 1)
  1619.         newmis.avelocity='400 250 300';
  1620.     if (spin == 2)
  1621.         newmis.avelocity='300 400 250';
  1622.     if (spin == 3)
  1623.         newmis.avelocity='300 300 300';
  1624.     if (spin >= 4) 
  1625.         newmis.avelocity='400 250 400';
  1626.  
  1627.     setmodel (newmis, "progs/grenade.mdl");
  1628.     setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
  1629.     setorigin (newmis, org);
  1630. };
  1631.  
  1632. //=========================================================================
  1633. // Thrown Grenade touch function.
  1634. void() NormalGrenadeTouch =
  1635. {
  1636.     if (other == self.owner)
  1637.         return;        // don't explode on owner
  1638.  
  1639.     // Thrown grenades don't detonate when hitting an enemy
  1640.  
  1641.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);    // bounce sound
  1642.     if (self.velocity == '0 0 0')
  1643.         self.avelocity = '0 0 0';
  1644. };
  1645.  
  1646. //=========================================================================
  1647. // Thrown grenade explosion. Twice as powerful as grenade launcher grenades.
  1648. void() NormalGrenadeExplode =
  1649. {
  1650.     T_RadiusDamage (self, self.owner, 240, world);
  1651.  
  1652.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1653.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  1654.     WriteCoord (MSG_BROADCAST, self.origin_x);
  1655.     WriteCoord (MSG_BROADCAST, self.origin_y);
  1656.     WriteCoord (MSG_BROADCAST, self.origin_z);
  1657.  
  1658.     BecomeExplosion ();
  1659. };
  1660.  
  1661. //=========================================================================
  1662. // Detonate all thrown pipebombs
  1663. void() TeamFortress_DetonatePipebombs =
  1664. {
  1665.     local entity e;
  1666.  
  1667. // Find all this players pipebombs
  1668.     e = find(world, classname, "pipebomb");
  1669.     while (e)
  1670.     {
  1671.         if(e.owner == self)
  1672.             e.nextthink = time;
  1673.         
  1674.         e = find(e, classname, "pipebomb");
  1675.     }
  1676. };
  1677.  
  1678. //=========================================================================
  1679. // Pipebomb touch function
  1680. void() PipebombTouch =
  1681. {
  1682.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);    // bounce sound
  1683.     if (self.velocity == '0 0 0')
  1684.         self.avelocity = '0 0 0';
  1685. };
  1686.  
  1687. //=========================================================================
  1688. // ITEM HANDLING FUNCTIONS
  1689. //=========================================================================
  1690. //=========================================================================
  1691. // Handles the scanner function for scouts, and Base Defences
  1692. void(float scanrange) TeamFortress_Scan = 
  1693. {
  1694.     local string power;
  1695.     local entity list;
  1696.     local float scen, scfr;
  1697.  
  1698.     // added in for the direction scanner code
  1699.     local float enemy_detected;
  1700.     local float any_detected;
  1701.  
  1702.     local vector vf, vr, e;  // transformed versions of v_forward, v_right and the enemy vector
  1703.     local float res1, res2, res3; // for the vector work
  1704.     local float vf_e_angle, vr_e_angle; // results
  1705.  
  1706.     // prevent scan impulse from triggering anything else
  1707.     self.impulse = 0;
  1708.     self.last_impulse = 0;
  1709.  
  1710.     if (self.classname == "player")
  1711.     {
  1712.         if (!(self.tf_items & NIT_SCANNER))
  1713.             return;
  1714.  
  1715.         // If Impulse is TF_SCAN_ENEMY, toggle Scanning for Enemies
  1716.         if (scanrange == TF_SCAN_ENEMY)
  1717.         {
  1718.             if (self.tf_items_flags & NIT_SCANNER_ENEMY)
  1719.             {
  1720.                 sprint(self, "Enemy Scanning disabled.\n");
  1721.                 self.tf_items_flags = self.tf_items_flags - NIT_SCANNER_ENEMY;
  1722.                 return;
  1723.             }
  1724.             sprint(self, "Enemy Scanning enabled.\n");
  1725.             self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_ENEMY;
  1726.             return;
  1727.         }
  1728.  
  1729.         // If Impulse is TF_SCAN_FRIENDLY, toggle Scanning for Friendlies
  1730.         if (scanrange == TF_SCAN_FRIENDLY)
  1731.         {
  1732.             if (self.tf_items_flags & NIT_SCANNER_FRIENDLY)
  1733.             {
  1734.                 sprint(self, "Friendly Scanning disabled.\n");
  1735.                 self.tf_items_flags = self.tf_items_flags - NIT_SCANNER_FRIENDLY;
  1736.                 return;
  1737.             }
  1738.             sprint(self, "Friendly Scanning enabled.\n");
  1739.             self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_FRIENDLY;
  1740.             return;
  1741.         }
  1742.  
  1743.         // If the user doesn't have as many cells as he/she specified, just
  1744.         // use as many as they've got.
  1745.  
  1746.         if (scanrange > self.ammo_cells)
  1747.             scanrange = self.ammo_cells;
  1748.  
  1749.         if (scanrange <= 0)
  1750.         {
  1751.             sprint(self,"No cells.\n");
  1752.             return;
  1753.         }
  1754.  
  1755.         if (scanrange > NIT_SCANNER_MAXCELL)
  1756.             scanrange = NIT_SCANNER_MAXCELL;
  1757.  
  1758.         scen = 0;
  1759.         scfr = 0;
  1760.         // Set the Scanner flags
  1761.         if (self.tf_items_flags & NIT_SCANNER_ENEMY)
  1762.             scen = 1;
  1763.         if (self.tf_items_flags & NIT_SCANNER_FRIENDLY)
  1764.             scfr = 1;
  1765.  
  1766.         // If no entity type is enabled, don't scan
  1767.         if ((scen == 0) && (scfr == 0))
  1768.         {
  1769.             sprint(self,"All scanner functions are disabled.\n");
  1770.             return;
  1771.         }
  1772.  
  1773.         sprint(self, "Power Usage: ");
  1774.         power = ftos(scanrange);
  1775.         sprint(self, power);
  1776.         sprint(self, ". Scanning...\n");
  1777.  
  1778.         // Use up cells to power the scanner
  1779.         // additions:
  1780.         // altered this so scanner could be more easily tested
  1781.         self.ammo_cells = self.ammo_cells - rint(scanrange / 5);
  1782.         scanrange = scanrange * NIT_SCANNER_POWER;
  1783.  
  1784.         // Get the list of entities the scanner finds
  1785.         list = T_RadiusScan(self, scanrange, scen, scfr);
  1786.     }
  1787.     // Base Defence scanning code here
  1788.  
  1789.     // Reset the entity counts
  1790.     scen = 0;
  1791.     scfr = 0;
  1792.  
  1793.     // the vectors v_forward and v_right are required to 
  1794.     // 'triangulate' the enemies position
  1795.     makevectors(self.v_angle);
  1796.  
  1797.     // Walk the list
  1798.     // For now, just count the entities.
  1799.     // In the future, we'll display bearings :)
  1800.     // additions: the future is now!
  1801.     while (list)
  1802.     {
  1803.         // sets the enemy_detected flag to TRUE if not on your team, FALSE if so
  1804.         any_detected = TRUE; // this flag is set to false if bogie is moving
  1805.                              // too slow to be detected (and velocity checking is on)
  1806.  
  1807.         // If this scanner is a motion detector, don't record
  1808.         // object that don't have the required velocity to be detected.
  1809.         if (self.tf_items_flags & NIT_SCANNER_MOVEMENT)
  1810.         {
  1811.             if (vlen(list.velocity) > NIT_SCANNER_MIN_MOVEMENT)
  1812.             {
  1813.                 if ((list.team > 0) && (self.team > 0) && (list.team == self.team)) 
  1814.                 {
  1815.                     scfr = scfr + 1;
  1816.                     enemy_detected = FALSE;
  1817.                 }
  1818.                 else
  1819.                 {
  1820.                     scen = scen + 1;
  1821.                     enemy_detected = TRUE;
  1822.                 }
  1823.             }
  1824.             else
  1825.             {
  1826.                 any_detected = FALSE;
  1827.             }
  1828.         }
  1829.         else
  1830.         {
  1831.              if ((list.team > 0) && (self.team > 0) && (list.team == self.team))
  1832.             {
  1833.                 scfr = scfr + 1;
  1834.                 enemy_detected = FALSE;
  1835.             }
  1836.             else
  1837.             {
  1838.                 scen = scen + 1;
  1839.                 enemy_detected = TRUE;
  1840.             }
  1841.         }
  1842.  
  1843.         // this displays the direction of the detected player
  1844.         // using the cosine rule to find the angle   
  1845.         //  cos theta = A.B divided by |A||B|
  1846.         // it should return a value between 1 and -1
  1847.         if (any_detected)
  1848.         {
  1849.             if (enemy_detected)
  1850.                 sprint(self, "Enemy detected at ");
  1851.             else
  1852.                 sprint(self, "Comrade detected at ");
  1853.  
  1854.             // finding the angle from v_forward gives the forward-back angle
  1855.             vf = v_forward;
  1856.             vf_z = 0;
  1857.  
  1858.             // finding the angle from v_right gives the left-right angle
  1859.             vr = v_right;
  1860.             vr_z = 0;
  1861.             
  1862.             // make a vector from the player to the detected one
  1863.             e = list.origin - self.origin;
  1864.             e_z = 0;
  1865.    
  1866.             res1 = vlen(e);
  1867.             if (res1 > 1200)
  1868.                 sprint(self, "very far ");
  1869.             else if (res1 > 600)
  1870.                 sprint(self, "far ");
  1871.  
  1872.        
  1873.             // dot product of vf and e   (A.B)
  1874.             res1 = (vf_x * e_x) + (vf_y * e_y);
  1875.  
  1876.             // multiple the vector lengths of vf and e (eg |A||B| )
  1877.             res2 = vlen(vf);
  1878.             res3 = vlen(e);
  1879.             res2 = res2 * res3;
  1880.             
  1881.             // divide the results
  1882.             vf_e_angle = res1 / res2;
  1883.  
  1884.             // finding the inverse cos of this gives the angle
  1885.             // but we don't need to do that because we realise:
  1886.  
  1887.             // if res3 is 1, then the arcos would be 0 degrees (directly ahead)
  1888.             // if res3 is 0.7, then the arcos would be 45 degrees (forward and off to one side)
  1889.             // if res3 is 0, then the arcos would be 90 degrees (directly to the side)
  1890.             // if res3 is -1, the the arcos would be 180 degrees (directly behind)
  1891.  
  1892.             // to narrow it right down, we need to find the angle between the enemy and v_right
  1893.  
  1894.             res1 = (vr_x * e_x) + (vr_y * e_y);
  1895.             res2 = vlen(vr);
  1896.             res3 = vlen(e);
  1897.             res2 = res2 * res3;
  1898.             vr_e_angle = res1 / res2;
  1899.  
  1900.             // if the vr_e_angle is positive, then the enemy is on the right-hand side
  1901.             // otherwise it is on the left
  1902.             // if vr_e_angle is 0, then the enemy is either directly in front or behind
  1903.  
  1904.             // the o'clock value is determined by a degree range
  1905.             // eg 1 o'clock is cos 15deg to cos 45deg
  1906.             //    2 o'clock is cos 45deg to cos 75deg
  1907.             if (vr_e_angle > 0)
  1908.             {
  1909.                 if (vf_e_angle >= 0.96)            // cos15
  1910.                     sprint(self, "12");
  1911.                 else if (vf_e_angle >= 0.7)     // cos45
  1912.                     sprint(self, "1");
  1913.                 else if (vf_e_angle >= 0.25)    // cos75
  1914.                     sprint(self, "2");
  1915.                 else if (vf_e_angle >= -0.25)    // cos105
  1916.                     sprint(self, "3");
  1917.                 else if (vf_e_angle >= -0.7)    // cos135
  1918.                     sprint(self, "4");
  1919.                 else if (vf_e_angle >= -0.96)      // cos165
  1920.                     sprint(self, "5");
  1921.                 else
  1922.                     sprint(self, "6");
  1923.             }
  1924.             else if (vr_e_angle < 0)
  1925.             {
  1926.                 if (vf_e_angle >= 0.96)
  1927.                     sprint(self, "12");
  1928.                 else if (vf_e_angle >= 0.7)
  1929.                     sprint(self, "11");
  1930.                 else if (vf_e_angle >= 0.25)
  1931.                     sprint(self, "10");
  1932.                 else if (vf_e_angle >= -0.25)
  1933.                     sprint(self, "9");
  1934.                 else if (vf_e_angle >= -0.7)
  1935.                     sprint(self, "8");
  1936.                 else if (vf_e_angle >= -0.96)
  1937.                     sprint(self, "7");
  1938.                 else
  1939.                     sprint(self, "6");
  1940.                     
  1941.             }
  1942.             else // vr_e_angle must be 0
  1943.             {
  1944.                 if (vf_e_angle < 0)
  1945.                     sprint(self, "12");
  1946.                 else
  1947.                     sprint(self, "6");
  1948.             }
  1949.  
  1950.  
  1951.             sprint(self, " o'clock");
  1952.  
  1953.             // do the up-down (z) direction
  1954.             res1 = list.origin_z - self.origin_z;
  1955.  
  1956.             if (res1 > 200)
  1957.                 sprint(self, ", really high");
  1958.             else if (res1 > 60)
  1959.                 sprint(self, ", high");
  1960.             else if (res1 < -200)
  1961.                 sprint(self, ", really low");
  1962.             else if (res1 < -60)
  1963.                 sprint(self, ", low");
  1964.             
  1965.             sprint(self, "\n");
  1966.         } // end if(any_detected)
  1967.  
  1968.  
  1969.         list = list.linked_list;
  1970.     }
  1971.  
  1972.     // Display the counts
  1973.     // For Base Defences, it will display the counts to all team members
  1974.     if ((scen == 0) && (scfr == 0))
  1975.     {
  1976.         sprint(self, "No blips.\n");
  1977.         return;
  1978.     }
  1979.  
  1980.     // Update ammo levels
  1981.     W_SetCurrentAmmo ();
  1982.  
  1983.     return;
  1984. };
  1985.  
  1986. //=========================================================================
  1987. // Handles the Setting of Detpacks
  1988. void(float timer) TeamFortress_SetDetpack =
  1989. {
  1990.     local string stimer;
  1991.     local entity detp;
  1992.  
  1993.     // prevent detpack impulse from triggering anything else
  1994.     self.impulse = 0;
  1995.     self.last_impulse = 0;
  1996.  
  1997.     if (!(self.secondary_items & NIT_DETPACK))
  1998.         return;
  1999.  
  2000.     if (self.ammo_detpack <= 0)
  2001.         return;
  2002.  
  2003.     self.ammo_detpack = self.ammo_detpack - 1;
  2004.     stuffcmd(self, "cl_forwardspeed 0\n");
  2005.     stuffcmd(self, "cl_backspeed 0\n");
  2006.     stuffcmd(self, "cl_sidespeed 0\n");
  2007.  
  2008.     sprint(self, "Setting detpack for ");
  2009.     stimer = ftos(timer);
  2010.     sprint(self, stimer);
  2011.     sprint(self, " seconds...\n");
  2012.  
  2013.     detp = spawn();
  2014.     detp.owner = self;
  2015.     detp.classname = "timer";
  2016.     detp.nextthink = time + NIT_DETPACK_SETTIME;
  2017.     detp.think = TeamFortress_DetpackSet;
  2018.     detp.health = timer;
  2019. };
  2020.  
  2021. //=========================================================================
  2022. // The detpack is set, let the player go and start timer
  2023. void() TeamFortress_DetpackSet =
  2024. {
  2025.     local entity countd, dp;
  2026.  
  2027.     TeamFortress_SetSpeed();
  2028.  
  2029.     dp = spawn ();
  2030.     dp.owner = self.owner;
  2031.     dp.origin = self.owner.origin - '0 0 23';
  2032.     dp.movetype = MOVETYPE_BOUNCE;
  2033.     dp.solid = SOLID_TRIGGER;
  2034.     dp.classname = "detpack";
  2035.     dp.flags = FL_ITEM;
  2036.         
  2037.     dp.velocity = '0 0 0';
  2038.     dp.avelocity = '0 0 0';
  2039.     dp.angles = vectoangles(dp.velocity);
  2040.  
  2041.     // Set the Detpack alternative kill flag
  2042.     dp.tfstate = dp.tfstate | TFSTATE_ALTKILL;
  2043.     dp.altkillweapon = AK_DETPACK;
  2044.  
  2045.        dp.touch = TeamFortress_DetpackTouch;
  2046.  
  2047.     setmodel (dp, "progs/backpack.mdl");
  2048.     setsize (dp, '-16 -16 0', '16 16 56');        
  2049.     setorigin (dp, self.owner.origin);
  2050.  
  2051.     // Create the CountDown entity
  2052.     countd = spawn();
  2053.     countd.think = TeamFortress_DetpackCountDown;
  2054.     countd.health = self.health - 1;
  2055.     countd.owner = self.owner;
  2056.     if (self.health <= 10)
  2057.         countd.nextthink = time + 1;
  2058.     else
  2059.     {
  2060.         countd.nextthink = time + self.health - 10;
  2061.         countd.health = 9;
  2062.     }
  2063.     dp.nextthink = time + self.health;
  2064.     dp.think = TeamFortress_DetpackExplode;
  2065.  
  2066.     sprint(self.owner, "Detpack set!\n");
  2067.     remove(self);
  2068. };
  2069.  
  2070. //=========================================================================
  2071. // The detpack goes BOOM!
  2072. void() TeamFortress_DetpackExplode = 
  2073. {
  2074.     bprint("FIRE IN THE HOLE!!!!\n");
  2075.     T_RadiusDamage (self, self.owner, NIT_DETPACK_SIZE, world);
  2076.  
  2077.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  2078.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  2079.     WriteCoord (MSG_BROADCAST, self.origin_x);
  2080.     WriteCoord (MSG_BROADCAST, self.origin_y);
  2081.     WriteCoord (MSG_BROADCAST, self.origin_z);
  2082.  
  2083.     BecomeExplosion ();
  2084. };
  2085.  
  2086. //=========================================================================
  2087. // The detpack touch function. Scouts can disarm it
  2088. void() TeamFortress_DetpackTouch = 
  2089. {
  2090.     if (other.classname != "player")
  2091.         return;
  2092.  
  2093.     if (other.playerclass != PC_SCOUT)
  2094.         return;
  2095.  
  2096.     bprint(other.netname);
  2097.     bprint(" snuffs ");
  2098.     bprint(self.owner.netname);
  2099.     bprint("'s fuse!\n");
  2100.  
  2101.     remove(self);
  2102. };
  2103.  
  2104. //=========================================================================
  2105. // The Detpack CountDown function. Displays the seconds left before the
  2106. // detpack detonates to the owner of the detpack, if <10
  2107. void() TeamFortress_DetpackCountDown = 
  2108. {
  2109.     local string cd;
  2110.  
  2111.     cd = ftos(self.health);
  2112.     sprint(self.owner, cd);
  2113.     sprint(self.owner, "...\n");
  2114.  
  2115.     self.nextthink = time + 1;
  2116.     self.health = self.health - 1;
  2117.  
  2118.     if (self.health == 0)
  2119.         remove(self);
  2120. };
  2121.  
  2122. //========================================================================
  2123. // Function for handling the BioInfection Decay of players
  2124. void() BioInfection_Decay =
  2125. {
  2126.     
  2127.     self.nextthink = time + 2;
  2128.  
  2129.     TF_T_Damage(self.owner, self, self.enemy, 5, TF_TD_IGNOREARMOUR);
  2130.     SpawnBlood(self.owner.origin, '0 0 0', 30);
  2131.  
  2132.     // remove this entity if the infection is gone
  2133.     if ( !(self.owner.tfstate & TFSTATE_INFECTED) )
  2134.         remove(self);
  2135. };
  2136.  
  2137. //========================================================================
  2138. // Function for handling the BioInfection Decay of monsters
  2139. void() BioInfection_MonsterDecay =
  2140. {
  2141.     self.nextthink = time + 2;
  2142.  
  2143.     T_Damage(self.enemy, self, self.owner, 5);
  2144.     SpawnBlood(self.enemy.origin, '0 0 0', 20);
  2145.     
  2146.     if (self.enemy.health < 1)
  2147.         remove(self);
  2148.         
  2149. };
  2150.  
  2151. //=========================================================================
  2152. // UTILITY FUNCTIONS
  2153. //=========================================================================
  2154. //=========================================================================
  2155. // Acts just like T_RadiusDamage, but doesn't damage things, just pushes them away
  2156. // from the explosion at a speed relative to the distance from the explosion's origin.
  2157. void(entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce =
  2158. {
  2159.     local    float     points;
  2160.     local    entity    head, te;
  2161.     local    vector    org;
  2162.     local    string    st;
  2163.  
  2164.     head = findradius(inflictor.origin, bounce+40);
  2165.     
  2166.     while (head)
  2167.     {
  2168.         if (head != ignore)
  2169.         {
  2170.             if (head.takedamage)
  2171.             {
  2172.                 org = head.origin + (head.mins + head.maxs)*0.5;
  2173.                 points = 0.5*vlen (org - inflictor.origin);
  2174.                 if (points < 0)
  2175.                     points = 0;
  2176.                 points = bounce - points;
  2177.                 if (points > 0)
  2178.                 {
  2179.                     // Bounce!!
  2180.                     head.velocity = org - inflictor.origin;
  2181.                     head.velocity = head.velocity * (points / 10);
  2182.  
  2183.                     if (head.classname != "player")
  2184.                     {
  2185.                         if(head.flags & FL_ONGROUND)
  2186.                             head.flags = head.flags - FL_ONGROUND;
  2187.                     }
  2188.                     else
  2189.                     {
  2190.                         // Concuss 'em!!
  2191.                         // If they are already concussed, set the concussion back up
  2192.                         // Try to find a concusstimer entity for this player
  2193.                         te = find(world, classname, "timer");
  2194.                         while (((te.owner != head) || (te.think != ConcussionGrenadeTimer)) && (te != world))
  2195.                             te = find(te, classname, "timer");
  2196.                         if (te != world)
  2197.                         {
  2198.                             stuffcmd(head,"v_idlescale 100\n");
  2199.                             te.health = 100;
  2200.                             te.nextthink = time + GR_CONCUSS_TIME;
  2201.                         }
  2202.                         else
  2203.                         {
  2204.                             stuffcmd(head,"v_idlescale 100\n");
  2205.                             stuffcmd(head,"bf\n");
  2206.                             // Create a timer entity
  2207.                             te = spawn();
  2208.                             te.nextthink = time + GR_CONCUSS_TIME;
  2209.                             te.think = ConcussionGrenadeTimer;
  2210.                             te.classname = "timer";
  2211.                             te.owner = head;
  2212.                             te.health = 100;
  2213.                         }
  2214.                     }
  2215.                 }
  2216.             }
  2217.         }
  2218.         head = head.chain;
  2219.     }
  2220. };
  2221.  
  2222. //=========================================================================
  2223. // Returns a list of players within a radius around the origin, like findradius,
  2224. // except that some parsing of the list can be done based on the parameters passed in.
  2225. // Make sure you check that the return value is not NULL b4 using it.
  2226. entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan =
  2227. {
  2228.     local entity head;
  2229.     local entity list_head;
  2230.     local entity list;
  2231.     local float gotatarget;
  2232.  
  2233.     head = findradius(scanner.origin, scanrange+40);
  2234.  
  2235.     while (head)
  2236.     {
  2237.         gotatarget = 0;
  2238.         if (head != scanner)            // Don't pick up the entity that's scanning
  2239.         {
  2240.             if (head.takedamage)
  2241.             {
  2242.                 if ((head.classname == "player") && (friends || enemies))
  2243.                 {
  2244.                     if (teamplay == 1)
  2245.                     {
  2246.                         if ( friends && (head.team > 0) && (scanner.team > 0) && (head.team == scanner.team) )
  2247.                             gotatarget = 1;
  2248.                         if ( enemies && (head.team > 0) && (scanner.team > 0) && (head.team != scanner.team) )
  2249.                             gotatarget = 1;
  2250.                     }
  2251.                     else
  2252.                         gotatarget = 1;
  2253.                 }
  2254.             }
  2255.         }
  2256.  
  2257.         // Add this entity to the linked list if it matches the target criteria
  2258.         if (gotatarget)
  2259.         {
  2260.             if (list)
  2261.             {
  2262.                 list.linked_list = head;
  2263.                 list = list.linked_list;
  2264.             }
  2265.             else
  2266.             {
  2267.                 list_head = head;
  2268.                 list = head;
  2269.             }
  2270.         }
  2271.  
  2272.         head = head.chain;
  2273.     }
  2274.  
  2275.     return list_head;
  2276. };
  2277.  
  2278. //=========================================================================
  2279. // Stuff an alias. This is a little messy since we insisted
  2280. // on maintaining the ability to alter the impulse numbers in the defs.qc 
  2281. // and not have to change any code. 
  2282. void(string halias, float himpulse1, float himpulse2) TeamFortress_Alias =
  2283. {
  2284.     local string imp;
  2285.  
  2286.     stuffcmd(self, "alias ");
  2287.     stuffcmd(self, halias);
  2288.     stuffcmd(self, " \"impulse ");
  2289.     imp = ftos(himpulse1);
  2290.     stuffcmd(self, imp);
  2291.  
  2292.     // if himpulse2 is not zero, assume that himpulse1 is a preimpulse 
  2293.     // and complete the alias
  2294.     if (himpulse1)
  2295.     {
  2296.         stuffcmd(self, ";wait; impulse ");
  2297.         imp = ftos(himpulse2);
  2298.         stuffcmd(self, imp);
  2299.     }
  2300.     stuffcmd(self, "\"\n");
  2301. };
  2302.  
  2303. //=========================================================================
  2304. // CYCLIC EVENT FUNCTIONS
  2305. //=========================================================================
  2306. //=========================================================================
  2307. // Regenerates the entity which owns this cyclictimer
  2308. void() TeamFortress_Regenerate =
  2309. {
  2310.     if (self.owner.playerclass == PC_MEDIC)
  2311.     {
  2312.         self.nextthink = time + PC_MEDIC_REGEN_TIME;
  2313.  
  2314.         if (self.owner.health >= self.owner.max_health)
  2315.             return;
  2316.  
  2317.         self.owner.health = self.owner.health + PC_MEDIC_REGEN_AMOUNT;
  2318.         if (self.owner.health > self.owner.max_health)
  2319.             self.owner.health = self.owner.max_health;
  2320.         return;
  2321.     }
  2322.  
  2323.     return;
  2324. };
  2325.  
  2326. //=========================================================================
  2327. // Check for cheats :) Mainly for internet play
  2328. // This is _far_ from a good solution. It will catch non-scouts that
  2329. // set their speeds to maxspeed, but not much else.
  2330. // It will occasionally catch someone who only sets their speed up 
  2331. // by a little bit.
  2332. // Still, in my opinion it was better than not checking at all.
  2333. // If anyone knows of a better way to do this, or knows how to
  2334. // get the value of a _client_ cvar, please mail me.
  2335. void() TeamFortress_CheckforCheats =
  2336. {
  2337.     local float tf;
  2338.     local string st;
  2339.  
  2340.     tf = random() * 50;
  2341.     self.nextthink = time + 10 + tf;
  2342.  
  2343.     tf = vlen(self.owner.velocity);
  2344.  
  2345.     // Since players still exceed their maxfbspeed when strafing
  2346.     // as well as moving forward or backward, I played around a
  2347.     // while until I decided on 300. I've never broken this.
  2348.     // If you do exceed this when not cheating, please mail me.
  2349.     if (tf > (self.owner.maxfbspeed + 300))
  2350.     {
  2351.         // Make sure they're on the ground
  2352.         if ((self.owner.flags & FL_ONGROUND) && (self.velocity_z == 0))
  2353.         {
  2354.             bprint(self.owner.netname);
  2355.             bprint(" has been fined 5 frags for cheating!\n");
  2356.             self.owner.frags = self.owner.frags - 5;
  2357.             T_Damage(self.owner, world, world, 400);
  2358.     
  2359.             // Make sure they don't get fined again before they respawn
  2360.             self.owner.maxfbspeed = 1000;
  2361.         }
  2362.      }
  2363.  };
  2364.  
  2365.